#include "stdc/stdc++.h"
using std::string;

//原型设计模式
//
//意向：允许您复制现有对象，而不使代码依赖于其类。

enum Type
{
    PROTOTYPE_1 = 0,
    PROTOTYPE_2
};

/**
 * 具有克隆能力的示例类。我们将看到字段的值如何克隆不同类型的。
 */

class Prototype
{
   protected:
    string prototype_name_;
    float prototype_field_;

   public:
    Prototype() {}
    Prototype(string prototype_name) : prototype_name_(prototype_name) {}
    virtual ~Prototype() {}
    virtual Prototype *Clone() const = 0;
    virtual void Method(float prototype_field)
    {
        this->prototype_field_ = prototype_field;
        std::cout << "Call Method from " << prototype_name_ << " with field : " << prototype_field << std::endl;
    }
};

/**
 * ConcretePrototype1 是 Prototype 的子类，并实现了 Clone 方法 在此示例中，Prototype Class 的所有数据成员都在 Stack 中。如果您的属性中有 ex： String*
 * name_ 的指针，则需要实现 Copy-Constructor 以确保您拥有 clone 方法的深层副本
 */

class ConcretePrototype1 : public Prototype
{
   private:
    float concrete_prototype_field1_;

   public:
    ConcretePrototype1(string prototype_name, float concrete_prototype_field)
        : Prototype(prototype_name), concrete_prototype_field1_(concrete_prototype_field)
    {}

    /**
     * 请注意，Clone 方法返回指向新 ConcretePrototype1
     * 副本的指针。因此，客户端（调用克隆方法）负责释放该内存。我有智能指针知识，你可能更喜欢在这里使用unique_pointer。
     */
    Prototype *Clone() const override
    {
        return new ConcretePrototype1(*this);
    }
};

class ConcretePrototype2 : public Prototype
{
   private:
    float concrete_prototype_field2_;

   public:
    ConcretePrototype2(string prototype_name, float concrete_prototype_field)
        : Prototype(prototype_name), concrete_prototype_field2_(concrete_prototype_field)
    {}
    Prototype *Clone() const override
    {
        return new ConcretePrototype2(*this);
    }
};

/**
 * 在PrototypeFactory中，你有两个具体的原型，每个具体的原型类一个，所以每次你想创建一个项目符号时，你都可以使用现有的原型并克隆它们。
 */

class PrototypeFactory
{
   private:
    std::unordered_map<Type, Prototype *, std::hash<int>> prototypes_;

   public:
    PrototypeFactory()
    {
        prototypes_[Type::PROTOTYPE_1] = new ConcretePrototype1("PROTOTYPE_1 ", 50.f);
        prototypes_[Type::PROTOTYPE_2] = new ConcretePrototype2("PROTOTYPE_2 ", 60.f);
    }

    /**
     * 注意释放所有分配的内存。同样，如果您有聪明的指针，最好在这里使用它。
     */

    ~PrototypeFactory()
    {
        delete prototypes_[Type::PROTOTYPE_1];
        delete prototypes_[Type::PROTOTYPE_2];
    }

    /**
     * 请注意，这里只需要指定所需的原型类型，该方法将从具有此类型的对象创建。
     */
    Prototype *CreatePrototype(Type type)
    {
        return prototypes_[type]->Clone();
    }
};

void Client(PrototypeFactory &prototype_factory)
{
    std::cout << "Let's create a Prototype 1\n";

    Prototype *prototype = prototype_factory.CreatePrototype(Type::PROTOTYPE_1);
    prototype->Method(90);
    delete prototype;

    std::cout << "\n";

    std::cout << "Let's create a Prototype 2 \n";

    prototype = prototype_factory.CreatePrototype(Type::PROTOTYPE_2);
    prototype->Method(10);

    delete prototype;
}

int main()
{
    PrototypeFactory *prototype_factory = new PrototypeFactory();
    Client(*prototype_factory);
    delete prototype_factory;

    return 0;
}